package com.jeeplus.common.utils.license;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import java.util.Map;

public abstract class RSAEnCoder{
public static final String KEY_ALGORITHM = "RSA";
public static final String KEY_PROVIDER = "BC";
public static final String SIGNATURE_ALGORITHM = "SHA1WithRSA";
	
	/**
	 * 初始化密钥对
	 */
	public static Map<String, Object> initKeys(String seed) throws Exception {
		Map<String, Object> keyMap = new HashMap<String, Object>();
		Security.addProvider(new BouncyCastleProvider());
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM, KEY_PROVIDER);
		
		keyPairGenerator.initialize(1024,new SecureRandom(seed.getBytes()));
		KeyPair pair = keyPairGenerator.generateKeyPair();
		RSAPublicKey rsaPublicKey = (RSAPublicKey) pair.getPublic();
		RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) pair.getPrivate();
		
		KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM,KEY_PROVIDER);
		RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(rsaPublicKey.getModulus().toString()),new BigInteger(rsaPublicKey.getPublicExponent().toString()));
		RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(rsaPrivateKey.getModulus().toString()),new BigInteger(rsaPrivateKey.getPrivateExponent().toString()));
		
		PublicKey publicKey = factory.generatePublic(pubKeySpec);
		PrivateKey privateKey = factory.generatePrivate(priKeySpec);
	
		System.out.println("公钥：" + pubKeySpec.getModulus() + "----" + pubKeySpec.getPublicExponent());
		System.out.println("私钥：" + priKeySpec.getModulus() + "----" + priKeySpec.getPrivateExponent());
		keyMap.put("publicKey", publicKey);
		keyMap.put("privateKey", privateKey);
		
		return keyMap;
	}
	
	/**
	 * 私钥加密
	 * */
	public static byte[] encryptRSA(byte[] data, PrivateKey privateKey) throws Exception {
		
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM,KEY_PROVIDER);
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);
		int dataSize = cipher.getOutputSize(data.length);
		// 获得加密块大小，如：加密前数据为128个byte，
        // 而key_size=1024 加密块大小为127
        // byte
        // ,加密后为128个byte;因此共有2个加密块
        // ，第一个127 byte第二个为1个byte
		
		int blockSize = cipher.getBlockSize(); // 获得加密块加密后块大小
		int blockNum = 0;
		if (data.length % blockSize == 0) {
			blockNum = data.length / blockSize;
		} else {
			blockNum = data.length / blockSize + 1;
		}
		byte[] raw = new byte[dataSize * blockNum];
		int i = 0;
		while (data.length - i * blockSize > 0) {
			if (data.length - i * blockSize > blockSize) {
				cipher.doFinal(data, i * blockSize, blockSize, raw, i * dataSize);
			} else {
				cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * dataSize);
			}
			i++;
		}
		
		return raw;
	}
 
	/**
	 * 生成数字签名
	 * */
	public static String sign(byte[] encoderData, PrivateKey privateKey) throws Exception {
		
		Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM,KEY_PROVIDER);
		sig.initSign(privateKey);
		sig.update(encoderData);
		return new String(Base64.encodeBase64(sig.sign()));
	}
	
	/**
	 * 校验数字签名
	 * */
	public static boolean verify (byte[] encoderData, String sign, PublicKey publicKey) throws Exception {
		
		Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM,KEY_PROVIDER);
		sig.initVerify(publicKey);
		sig.update(encoderData);
		return sig.verify(Base64.decodeBase64(sign.getBytes()));
	}
	
	 
	/** 
	 * 使用模和指数生成RSA私钥 
	 * @param modulus  模 
	 * @param exponent  指数 
	 * @return 
	 */
	public static PrivateKey getPrivateKey(String modulus, String exponent) throws Exception {
	        BigInteger b1 = new BigInteger(modulus);
	        BigInteger b2 = new BigInteger(exponent);
	        Security.addProvider(new BouncyCastleProvider());
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, KEY_PROVIDER);
	        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
	        return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
	}  

}